package com.wlsk.license.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.wlsk.license.common.constant.RedisService;
import com.wlsk.license.common.enums.StatusEnum;
import com.wlsk.license.common.result.Result;
import com.wlsk.license.dao.entity.SysDict;
import com.wlsk.license.dao.mapper.SysDictMapper;
import com.wlsk.license.dto.request.UserReqDto;
import com.wlsk.license.dto.request.feign.DeptByOrgReqDto;
import com.wlsk.license.dto.request.feign.OrgReqDto;
import com.wlsk.license.dto.response.DictDataResultDto;
import com.wlsk.license.dto.response.feign.*;
import com.wlsk.license.service.ISysDictService;
import com.wlsk.license.service.feign.MerchantFeignClient;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * <p>
 * 字典表 服务实现类
 * </p>
 *
 * @author liuzhangbin
 * @since 2025-08-26
 */
@Slf4j
@Service
public class SysDictServiceImpl extends ServiceImpl<SysDictMapper, SysDict> implements ISysDictService {

    @Autowired
    private MerchantFeignClient merchantFeignClient;

    @Autowired
    private RedisService redisService;

    /**
     * 商户组织树缓存key
     */
    private final static String ORG_TREE = "LICENSE:MERCHANT:ORG_TREE:%s";

    /**
     * 根据类型查询字典数据(集合)
     *
     * @param dictType 字典类型
     * @return
     */
    @Override
    public List<DictDataResultDto> getListByType(String dictType) {
        List<SysDict> dicts = this.baseMapper.selectList(Wrappers.<SysDict>lambdaQuery().eq(SysDict::getDictType, dictType).eq(SysDict::getStatus, StatusEnum.ON).orderByAsc(SysDict::getDictSort));
        List<DictDataResultDto> dictDataResultDtos = BeanUtil.copyToList(dicts, DictDataResultDto.class);
        return Optional.ofNullable(dictDataResultDtos).orElse(Collections.emptyList());
    }

    /**
     * 根据类型查询字典数据(单个)
     *
     * @param dictType 字典类型
     * @return
     */
    @Override
    public DictDataResultDto getOneByType(String dictType) {
        SysDict dict = this.baseMapper.selectOne(Wrappers.<SysDict>lambdaQuery().eq(SysDict::getDictType, dictType).eq(SysDict::getStatus, StatusEnum.ON));
        return BeanUtil.copyProperties(dict, DictDataResultDto.class);
    }

    @Override
    public DictDataResultDto getOneByTypeAndValue(String dictType, String dictValue) {
        SysDict dict = this.baseMapper.selectOne(Wrappers.<SysDict>lambdaQuery().eq(SysDict::getDictType, dictType).eq(SysDict::getDictValue, dictValue).eq(SysDict::getStatus, StatusEnum.ON));
        return BeanUtil.copyProperties(dict, DictDataResultDto.class);
    }

    /**
     * 查询所有字典数据并按类型分组
     *
     * @return 按字典类型分组的字典数据列表
     */
    @Override
    public Map<String, List<DictDataResultDto>> getAllGroupedByType() {
        // 查询所有启用状态的字典数据
        List<SysDict> dicts = this.baseMapper.selectList(
                Wrappers.<SysDict>lambdaQuery()
                        .eq(SysDict::getStatus, StatusEnum.ON)
                        .orderByAsc(SysDict::getDictType)
                        .orderByAsc(SysDict::getDictSort)
        );

        // 转换为 DTO 对象
        List<DictDataResultDto> dictDataResultDtos = BeanUtil.copyToList(dicts, DictDataResultDto.class);

        // 按字典类型分组
        return Optional.ofNullable(dictDataResultDtos)
                .orElse(Collections.emptyList())
                .stream()
                .collect(Collectors.groupingBy(DictDataResultDto::getDictType));
    }

    @Override
    public List<OrgTreeResVo> orgList(UserReqDto reqDto) {
        List<OrgTreeResVo> orgResVos = getRedisOrgList(reqDto);
        if(CollectionUtils.isNotEmpty(orgResVos)) {
            return orgResVos;
        }
        Map<Long, List<DepartResVo>> orgDepartMap = new HashMap<>();
        OrgReqDto orgVo = OrgReqDto.builder().uid(reqDto.getUid()).build();
        Result<UserOrgResVo> result = merchantFeignClient.getOrgByUserId(orgVo);
        if (result.isSuccess()) {
            UserOrgResVo resVo = result.getData();
            List<Long> orgIdList = new ArrayList<>();
            orgResVos = result.getData().getOrgs();
            traverseList(orgResVos, orgIdList);
            DepartResVo deptVo = resVo.getDeptVo();
            if(deptVo != null) {
                orgIdList.remove(deptVo.getParentId());
            }
            List<DepartResVo> departResVoList = new ArrayList<>();
            Result<List<DepartResVo>> departRes = merchantFeignClient.getDeptListByOrg(DeptByOrgReqDto.builder().orgIds(orgIdList).build());
            if(departRes.isSuccess()) {
                departResVoList = departRes.getData();
            }
            if(CollectionUtils.isNotEmpty(departResVoList)) {
                orgDepartMap = departResVoList.stream().collect(Collectors.groupingBy(DepartResVo::getParentId));
            }
            // 构建返回结果
            buildOrgResultDto(orgResVos, orgDepartMap, deptVo);
        }
        setRedisOrgList(reqDto, orgResVos);
        return orgResVos;
    }

    /**
     * 查询用户机构列表，如果当前用户挂在部门下则用户只能查询子机构
     * @param uid
     * @return
     */
    @Override
    public List<Long> userOrgIdList(Long uid) {
        List<Long> orgIdList = new ArrayList<>();
        List<OrgTreeResVo> orgList = orgList(UserReqDto.builder().uid(uid).build());
        getOrgIdList(orgList, orgIdList);
        return orgIdList;
    }

    /**
     * 获取用户部门列表，如果用户存在部门，怎可查询当前部门和子机构部门信息
     * @param uid
     * @return
     */
    @Override
    public List<Long> userDeptIdList(Long uid) {
        List<OrgTreeResVo> orgList = orgList(UserReqDto.builder().uid(uid).build());
        List<Long> departIdList = new ArrayList<>();
        getDepartIdList(orgList, departIdList);
        return departIdList;
    }

    @Override
    public void clearOrgCache(String uid) {
        if(uid != null && uid.equals("all")) {
            Collection<String> keys = redisService.keys(String.format(ORG_TREE, "*"));
            if(CollectionUtils.isNotEmpty(keys)) {
                for(String key : keys) {
                    redisService.deleteObject(key);
                }
            }
        }else if(StringUtils.isNotEmpty(uid)) {
            redisService.deleteObject(String.format(ORG_TREE, uid));
        }
    }

    private void traverseList(List<OrgTreeResVo> orgResVos, List<Long> orgIdList) {
        if(CollectionUtils.isNotEmpty(orgResVos)) {
            for(OrgTreeResVo org : orgResVos) {
                orgIdList.add(org.getOrgId());
                if(CollectionUtils.isNotEmpty(org.getChildren())) {
                    traverseList(org.getChildren(), orgIdList);
                }
            }
        }
    }

    private void buildOrgResultDto(List<OrgTreeResVo> orgResVos, Map<Long, List<DepartResVo>> orgDepartMap, DepartResVo current) {
        if(CollectionUtils.isNotEmpty(orgResVos)) {
            for(OrgTreeResVo org : orgResVos) {
                org.setDepartList(orgDepartMap.get(org.getOrgId()));
                if(CollectionUtils.isNotEmpty(org.getChildren())) {
                    buildOrgResultDto(org.getChildren(), orgDepartMap, current);
                } else if(current != null) {
                    if(org.getOrgId().equals(current.getParentId())) {
                        org.setDepartList(orgDepartMap.get(current.getParentId()));
                    }
                }
            }
        }
    }

    private List<OrgTreeResVo> getRedisOrgList(UserReqDto reqDto) {
        List<OrgTreeResVo> orgResVos = new ArrayList<>();
        try {
            String key = String.format(ORG_TREE, reqDto.getUid());
            orgResVos = redisService.getCacheList(key);
        } catch (Exception e) {
            log.error("查询商户组织树异常:{}",reqDto, e);
        }
        return orgResVos;
    }

    private void setRedisOrgList(UserReqDto reqDto, List<OrgTreeResVo> orgResVos) {
        try {
           if(CollectionUtils.isNotEmpty(orgResVos)) {
               String key = String.format(ORG_TREE, reqDto.getUid());
               redisService.setCacheList(key, orgResVos);
               redisService.expire(key, 1, TimeUnit.DAYS);
               log.info("设置商户组织树成功:{}",reqDto);
           }
        } catch (Exception e) {
            log.error("设置商户组织树异常:{}",reqDto, e);
        }
    }

    private void getOrgIdList(List<OrgTreeResVo> orgList, List<Long> orgIdList) {
        if(CollectionUtils.isNotEmpty(orgList)) {
            for(OrgTreeResVo org : orgList) {
                orgIdList.add(org.getOrgId());
                if(CollectionUtils.isNotEmpty(org.getChildren())) {
                    getOrgIdList(org.getChildren(), orgIdList);
                }
            }
        }
    }

    private void getDepartIdList(List<OrgTreeResVo> orgList, List<Long> departIdList) {
        if(CollectionUtils.isNotEmpty(orgList)) {
            for (OrgTreeResVo org : orgList) {
                if(CollectionUtils.isNotEmpty(org.getDepartList())) {
                    departIdList.addAll(org.getDepartList().stream().map(DepartResVo::getOrgId).collect(Collectors.toList()));
                }
                if(CollectionUtils.isNotEmpty(org.getChildren())) {
                    getDepartIdList(org.getChildren(), departIdList);
                }
            }
        }
    }
}
